﻿using BTechBids.Web.IDataAdapters.Adapters;
using BTechBids.Web.IDataAdapters.Interfaces;
using BTechBids.Web.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;

namespace BTechBids.Web.Singleton
{
    public class Singleton
    {
        private static readonly Singleton instance = new Singleton();
        private static IItemAdapter _adapter = new ItemAdapter();

        private bool isInitialized = false;
        private List<ActiveItem> ActiveItems;

        /// <summary>
        /// Adds a new item to the list of active items up for bid
        /// Starts the timer on the item
        /// </summary>
        /// <param name="ItemVM">The item to add to the active list</param>
        public void AddNewItem(ItemVM ItemVM)
        {
            if (!isInitialized)
            {
                return;
            }
            ActiveItem activeItem = new ActiveItem(ItemVM.msRemaining, ItemVM, Singleton.Instance);
            ActiveItems.Add(activeItem);
            activeItem.StartTimer();
        }

        /// <summary>
        /// Places a bid for the specified item
        /// </summary>
        /// <param name="id">Id of the item being bid on</param>
        /// <param name="userName">UserName of the bidder</param>
        /// <returns>Updated ItemQuickUpdateVM so the new bid can be displayed to user or null if the item is no longer active</returns>
        public ItemQuickUpdateVM MakeBid(int id, string userName)
        {
            if (!isInitialized)
            {
                return null;
            }
            ActiveItem item = ActiveItems.FirstOrDefault(x => x.GetItemVM().Id == id);
            if (item == null || item.TimeRemaining() <= 0)
            {
                return null;
            }

            ItemQuickUpdateVM updateItem = item.MakeBid(userName);

            // Consider making this async
            _adapter.UpdateItemOnBid(updateItem);
            return updateItem;
        }


        /// <summary>
        /// Get a list of view models for all active items when server first launches
        /// </summary>
        /// <returns>List of ItemVM</returns>
        public List<ItemVM> GetActiveItems()
        {
            if (!isInitialized)
            {
                return null;
            }

            List<ItemVM> items = ActiveItems.Select(x => x.GetItemVM()).ToList();
            return items;
        }

        /// <summary>
        /// Gets a quick update for the specified item
        /// </summary>
        /// <param name="id">Id of the item that an update is needed for</param>
        /// <returns>ItemQuickUpdateVM or else null if the item is no longer active</returns>
        public ItemQuickUpdateVM GetQuickUpdateForItem(int id)
        {
            if (!isInitialized)
            {
                return null;
            }
            ActiveItem activeItem = ActiveItems.FirstOrDefault(x => x.GetItemVM().Id == id);
            if (activeItem == null)
            {
                return null;
            }

            ItemVM item = activeItem.GetItemVM();

            ItemQuickUpdateVM updateItem = new ItemQuickUpdateVM()
            {
                Id = item.Id,
                Cost = item.Cost,
                UserName = item.UserName,
                msRemaining = activeItem.TimeRemaining()
            };
            return updateItem;
        }

        public List<ItemQuickUpdateVM> GetQuickUpdateItems()
        {
            if (!isInitialized)
            {
                return null;
            }
            List<ItemVM> items = ActiveItems.Select(x => x.GetItemVM()).ToList();

            List<ItemQuickUpdateVM> quickItems = items.Select(x => new ItemQuickUpdateVM()
            {
                Id = x.Id,
                Cost = x.Cost,
                UserName = x.UserName,
                msRemaining = x.msRemaining
            }).ToList();
            return quickItems;
        }

        /// <summary>
        /// Get details for a specific active item
        /// </summary>
        /// <param name="id">Id of the item</param>
        /// <returns>The ItemVM or null if item is no longer active</returns>
        public ItemVM GetItemIfActive(int id)
        {
            if (!isInitialized)
            {
                return null;
                //Start();
            }
            ActiveItem activeItem = ActiveItems.FirstOrDefault(x => x.GetItemVM().Id == id);
            if (activeItem == null)
            {
                return null;
            }
            ItemVM itemVM = activeItem.GetItemVM();
            return itemVM;

        }

        /// <summary>
        /// Finalizes the auction once the timer expires and calls this method
        /// If there are no bids on the item, it will recycle it and make a new ActiveItem
        /// </summary>
        /// <param name="activeItem">The ActiveItem with the expired timer</param>
        public void FinalizeAuction(ActiveItem activeItem)
        {
            ActiveItems.Remove(activeItem);
            _adapter.FinalizeAuctionForItem(activeItem.GetFinalizedItemVM());

            //if (activeItem.GetFinalizedItemVM().Cost <= 0.01)
            if (true)
            {
                ItemVM olditemvm = activeItem.GetFinalizedItemVM();
                ItemVM itemvm = new ItemVM()
                {
                    Name = olditemvm.Name,
                    Category = olditemvm.Category,
                    Cost = olditemvm.Cost,
                    Description = olditemvm.Description,
                    imageUrl = olditemvm.imageUrl,
                    msRemaining = 900000
                };
                itemvm = _adapter.AddItem(itemvm);
                AddNewItem(itemvm);
            }


        }
        public ItemVM DeleteAuction(int id)
        {
            if (!isInitialized)
            {
                return null;
            }
            ActiveItem activeItem = ActiveItems.FirstOrDefault(x => x.GetItemVM().Id == id);
            if (activeItem == null)
            {
                return null;
            }
            ItemVM itemVM = activeItem.GetItemVM();
            activeItem.StopTimer();
            ActiveItems.Remove(activeItem);
            return itemVM;
        }

        static Singleton()
        {
            Singleton.Instance.Start();
        }

        private Singleton()
        {
            Debug.WriteLine("Singleton created");
        }

        public static Singleton Instance
        {
            get
            {
                Debug.WriteLine("Singleton Instance");
                return instance;
            }
        }

        private void Start()
        {
            Debug.WriteLine("Singleton started");

            ActiveItems = _adapter.GetAllItems().Select(x => new ActiveItem(x.msRemaining, x, Singleton.Instance)).ToList();

            foreach (var activeItem in ActiveItems)
            {
                activeItem.StartTimer();
            }
            isInitialized = true;

        }
    }
}